#ifndef NANE_IRENDERSYSTEM_H
#   define NANE_IRENDERSYSTEM_H

#   include "nane/core/ISubSystem.h"
#   include "nane/core/types.h"
#   include "nane/core/enum.h"
#   include "nane/core/PixelFormat.h"
#   include "nane/WindowSystem/IWindowSystem.h"

namespace nane
{
    struct EResourceUsage
        : public Enum<EResourceUsage>
    {
        enum domain
        {
            Default = 0,
            Readonly,
            Writeonly,
            Readwrite,
            
            _max
        };
        
        NANE_ENUM( EResourceUsage, Enum );
    };

    struct EPrimitiveType
        : public Enum<EPrimitiveType>
    {
        enum domain
        {
            PointList = 0,
            LineList,
            LineStrip,
            TriangleList,
            TriangleStrip,
            TriangleFan,

            _max
        };
        
        NANE_ENUM( EPrimitiveType, Enum );
    };

    struct EFrameBufferType
        : public EnumBitwise<EFrameBufferType>
    {
        enum domain
        {
            Color = 0x1,
            Depth = 0x2,
            Stencil = 0x4,

            _max
        };
        
        NANE_ENUM( EFrameBufferType, EnumBitwise );
    };
    NANE_ENUM_BITWISE( EFrameBufferType );
    
    struct ITexture
    {
    };

    struct IRenderTarget
        : public ITexture
    {

    };

    struct IVertexBuffer
    {
    };

    struct IIndexBuffer
    {
    };

    struct EVertexElementSemantic
        : public Enum<EVertexElementSemantic>
    {
        enum domain
        {
            Position = 0,
            BlendWeight,   // 1
            BlendIndices,  // 2
            Normal,        // 3
            PSize,         // 4
            TexCoord,      // 5
            Tangent,       // 6
            Binormal,      // 7
            TessFactor,    // 8
            Color,         // 9
            Fog,           // 10
            Depth,         // 11
            Sample,        // 12
            
            _max
        };
        
        NANE_ENUM( EVertexElementSemantic, Enum );
    };

    struct EVertexElementType
        : public Enum<EVertexElementType>
    {
        enum domain
        {
            Float1    =  0,  // 1D float expanded to (value, 0., 0., 1.)
            Float2    =  1,  // 2D float expanded to (value, value, 0., 1.)
            Float3    =  2,  // 3D float expanded to (value, value, value, 1.)
            Float4    =  3,  // 4D float
            Color     =  4,  // 4D packed unsigned bytes mapped to 0. to 1. range (ARGB format expanded to [R, G, B, A])
            UByte4    =  5,  // 4D unsigned byte
            Short2    =  6,  // 2D signed short expanded to (value, value, 0., 1.)
            Short4    =  7,  // 4D signed short
            
            _max
        };
        
        NANE_ENUM( EVertexElementType, Enum );         
    };

    struct VertexElement
    {
        uint16 stream;
        uint32 offset;
        EVertexElementSemantic::raw_type semantic;
        EVertexElementType::raw_type type;
        byte usageIndex;
    };

    struct ECullMode
        : public Enum<ECullMode>
    {
        enum domain
        {
            None = 0,
            Clockwise,
            CounterClockwise,
                    
            _max
        };
        
        NANE_ENUM( ECullMode, Enum );
    };
    
    //
    // Constant buffer interface
    //
    struct IConstantBuffer
    {
        
    };
    
    //
    // Vertex shader interface
    //
    struct IVertexShader
    {
    };
    
    //
    // Pixel shader interface
    //
    struct IPixelShader
    {
    };

    struct IRenderSystem
        : public ISubSystem
    {
        virtual bool InitializeContext( IWindow::OSHandle _windowHandle, uint32 _resWidth, uint32 _resHeight ) = 0;
        virtual IVertexBuffer* CreateVertexBuffer( EResourceUsage::raw_type _usage, uint32 _verticesNum, uint32 _vertexSize
                                                 , VertexElement* _elements, uint32 _elementsNum, byte* _initData ) = 0;
        virtual void ReleaseVertexBuffer( IVertexBuffer* _vertexBuffer ) = 0;
        virtual byte* LockVertexBuffer( IVertexBuffer* _vertexBuffer, uint32 _offset, uint32 _size ) = 0;
        virtual void UnlockVertexBuffer( IVertexBuffer* _vertexBuffer ) = 0;
        virtual void SetVertexBuffer( uint16 _streamNumber, IVertexBuffer* _vertexBuffer ) = 0;
        virtual IIndexBuffer* CreateIndexBuffer( EResourceUsage::raw_type _usage, uint32 _indiciesNum, uint16* _initData ) = 0;
        virtual void ReleaseIndexBuffer( IIndexBuffer* _indexBuffer ) = 0;
        virtual uint16* LockIndexBuffer( IIndexBuffer* _indexBuffer, uint32 _offset, uint32 _size ) = 0;
        virtual void UnlockIndexBuffer( IIndexBuffer* _indexBuffer ) = 0;
        virtual void SetIndexBuffer( IIndexBuffer* _indexBuffer ) = 0;
        virtual ITexture* CreateTexture( EResourceUsage::raw_type _usage, uint32 _width, uint32 _height, EPixelFormat::raw_type _format ) = 0;
        virtual void ReleaseTexture( ITexture* _texture ) = 0;
        virtual byte* LockTexture( ITexture* _texture, uint32 _x, uint32 _y, uint32 _width, uint32 _height, uint32* _pitch ) = 0;
        virtual void UnlockTexture( ITexture* _texture ) = 0;
        virtual void SetTexture( uint32 _stage, ITexture* _texture ) = 0;
        virtual bool SetRenderTarget( IRenderTarget* _target ) = 0;
        virtual bool BeginScene() = 0;
        virtual void EndScene() = 0;
        virtual void DrawPrimitive( EPrimitiveType::raw_type _type, uint32 _startVertex, uint32 _primitiveCount ) = 0;
        virtual void DrawIndexedPrimitive( EPrimitiveType::raw_type _type, uint32 _baseVertexIndex, uint32 _minIndex
                                         , uint32 _verticesNum, uint32 _startIndex, uint32 _primitiveCount ) = 0;
        virtual void ClearRenderTarget( EFrameBufferType::raw_type _type, uint32 _color, float _depth, uint16 _stencil ) = 0;
        virtual void SwapBuffers() = 0;
        virtual void SetProjectionMatrix( const float* _projection ) = 0;
        virtual void SetModelViewMatrix( const float* _modelview ) = 0;
        virtual void SetLightingEnable( bool _enable ) = 0;
        virtual void SetCullMode( ECullMode::raw_type _mode ) = 0;
        
        //
        // creates constant buffer
        // -
        // precond:
        //   IRenderSystem context must be initialized
        // params:
        //   _size - size of constant buffer to create in bytes
        // result:
        //   returns non-null IConstantBuffer interface pointer if buffer was successfully created, otherwise - null
        //   non-null IConstantBuffer pointer must be released with 'ReleaseConstantBuffer' before SubSystem shutdown
        //
        virtual IConstantBuffer* CreateConstantBuffer( uint32 _size ) = 0;

        //
        // pushes constant to constant buffer
        // -
        // precond:
        //   IRenderSystem context must be initialized
        // params:
        //   _constantBuffer - non-null valid IConstantBuffer interface pointer returned by 'CreateConstantBuffer'
        //   _offset - offset from start of buffer in bytes
        //   _constant - non-null valid pointer to array of values
        //   _size - size of _constant array in bytes (_offset + _size must be less or equal buffer size provided in 'CreateConstantBuffer')
        // result:
        //   returns true if constant was successfully pushed into next buffer slot, otherwise - false
        //
        virtual bool PushConstantF( IConstantBuffer* _constantBuffer, uint32 _offset, float* _constant, uint32 _size ) = 0;
        virtual bool PushConstantI( IConstantBuffer* _constantBuffer, uint32 _offset, int* _constant, uint32 _size ) = 0;
        virtual bool PushConstantB( IConstantBuffer* _constantBuffer, uint32 _offset, bool* _constant, uint32 _size ) = 0;
        
        //
        // releases previously created constant buffer
        // -
        // precond:
        //   IRenderSystem context must be initialized
        //   buffer being released must not be set as current
        // params:
        //   _constantBuffer - non-null valid IConstantBuffer pointer returned by 'CreateConstantBuffer'
        // result:
        //   all resources assigned with _constantBuffer are released
        //
        virtual void ReleaseConstantBuffer( IConstantBuffer* _constantBuffer ) = 0;
        
        //
        // creates vertex shader
        // -
        // precond:
        //   IRenderSystem context must be initialized
        // params:
        //   _buffer - non-null valid buffer containing shader binary data in subsystem implementation specific format
        //   _size - size of shader data in bytes
        // result:
        //   returns non-null IVertexShader interface pointer if shader was successfully loaded, otherwise - null
        //   non-null IVertexShader pointer must be released with 'ReleaseVertexShader' before SubSystem shutdown
        //
        virtual IVertexShader* CreateVertexShader( const byte* _buffer, uint32 _size ) = 0;
        
        //
        // sets the current vertex shader to a previously created vertex shader
        // -
        // precond:
        //   IRenderSystem context must be initialized
        // params:
        //   _vertexShader - IPixelShader pointer returned by 'CreateVertexShader' or NULL to disable vertex shader stage
        // results:
        //   returns true if operation was successfull, otherwise - false
        //        
        virtual bool SetVertexShader( IVertexShader* _vertexShader ) = 0;
        
        //
        // sets vertex shader constants from constant buffer
        // -
        // precond:
        //   IRenderSystem context must be initialized
        // params:
        //   _slot - slot to set buffer at
        //   _constantBuffer - IConstantBuffer interface pointer containing constants or null to unbind current buffer
        // result:
        //   returns true if operation was successfull, otherwise - false
        //
        virtual bool SetVertexShaderConstantBuffer( uint32 _slot, IConstantBuffer* _constantBuffer ) = 0;
        
        //
        // releases previously created vertex shader
        // -
        // precond:
        //   IRenderSystem context must be initialized
        //   shader being released must not be set as current
        // params:
        //   _vertexShader - non-null valid IVertexShader pointer returned by 'CreateVertexShader'
        // results:
        //   all resources assigned with IVertexShader are released
        //        
        virtual void ReleaseVertexShader( IVertexShader* _vertexShader ) = 0;
        
        //
        // creates pixel shader
        // -
        // precond:
        //   IRenderSystem context must be initialized
        // params:
        //   _buffer - non-null valid buffer containing shader binary data in subsystem implementation specific format
        //   _size - size of shader data in bytes
        // result:
        //   returns non-null IPixelShader interface pointer if shader was successfully loaded, otherwise - null
        //   non-null IPixelShader pointer must be released with 'ReleasePixelShader' before SubSystem shutdown
        //
        virtual IPixelShader* CreatePixelShader( const byte* _buffer, uint32 _size ) = 0;
        
        //
        // sets the current pixel shader to a previously created pixel shader
        // -
        // precond:
        //   IRenderSystem context must be initialized
        // params:
        //   _pixelShader - IPixelShader pointer returned by 'CreatePixelShader' or NULL to disable pixel shader stage
        // results:
        //   returns true if operation was successfull, otherwise - false
        //
        virtual bool SetPixelShader( IPixelShader* _pixelShader ) = 0;
        
        //
        // sets pixel shader constants from constant buffer
        // -
        // precond:
        //   IRenderSystem context must be initialized
        // params:
        //   _slot - slot to set buffer at
        //   _constantBuffer - IConstantBuffer interface pointer containing constants or null to unbind current buffer
        // result:
        //   returns true if operation was successfull, otherwise - false
        //
        virtual bool SetPixelShaderConstantBuffer( uint32 _slot, IConstantBuffer* _constantBuffer ) = 0;
        
        //
        // releases previously created pixel shader
        // -
        // precond:
        //   IRenderSystem context must be initialized
        //   shader being released must not be set as current
        // params:
        //   _pixelShader - non-null valid IPixelShader pointer returned by 'CreatePixelShader'
        // results:
        //   all resources assigned with IPixelShader are released
        //
        virtual void ReleasePixelShader( IPixelShader* _pixelShader ) = 0;
    };
}

#endif	// NANE_IRENDERSYSTEM_H

